﻿using System;
using System.Linq;
using Sponsorship.Domain;
using Raven.Client;
using Sponsorship.Domain.Persons;
using Sponsorship.Domain.Sponsors;
using Sponsorship.Domain.Sponsorships;
using Sponsorship.ReadModel.Persons;

namespace Sponsorship.ReadModel.Sponsors
{
    public class DetailsOfSponsorEventHandler : 
            IEventHandler<SponsorEntered>,
            IEventHandler<SponsorChanged>,
            IEventHandler<SponsorDeleted>,
            IEventHandler<SponsorshipEntered>,
            IEventHandler<SponsorshipChanged>,
            IEventHandler<PersonChanged>
    {
        private readonly IDocumentStore _documentStore;

        public DetailsOfSponsorEventHandler (IDocumentStore documentStore)
        {
            _documentStore = documentStore;
        }

        public void Handle(SponsorEntered domainEvent)
        {
            using (IDocumentSession session = _documentStore.OpenSession())
            {
                var bankInformationDto = domainEvent.BankInformation != null ? CreateBankInformationDto(domainEvent.BankInformation) : null;
                var addressDto = domainEvent.Address != null ? CreateAddressDto(domainEvent.Address) : null;

                var dto = new DetailsOfSponsorDto
                {
                    AggregateRootId = domainEvent.SponsorId,
                    FirstName = domainEvent.FirstName,
                    LastName = domainEvent.LastName,
                    EMail = domainEvent.EMail,
                    TelephoneNumber = domainEvent.TelephoneNumber,
                    Comment = domainEvent.Comment,
                    BankInformation = bankInformationDto,
                    Address = addressDto,
                };

                session.Store(dto);

                session.SaveChanges(dto, domainEvent);
            }
        }

        private BankInformationDto CreateBankInformationDto(BankInformation bankInformation)
        {
            return new BankInformationDto
            {
                AccountNumber = bankInformation.AccountNumber,
                BankCode = bankInformation.BankCode,
                Iban = bankInformation.Iban,
                Swift = bankInformation.Swift
            };
        }

        private AddressDto CreateAddressDto(Address address)
        {
            return new AddressDto
            {
                Street = address.Street,
                Number = address.Number,
                City = address.City,
                Zip = address.Zip,
                Country = address.Country
            };
        }

        public void Handle(SponsorChanged domainEvent)
        {
            using (IDocumentSession session = _documentStore.OpenSession())
            {
                var dto = session.LoadById<DetailsOfSponsorDto>(domainEvent.SponsorId);
                dto.FirstName = domainEvent.FirstName;
                dto.LastName = domainEvent.LastName;
                dto.EMail = domainEvent.EMail;
                dto.TelephoneNumber = domainEvent.TelephoneNumber;
                dto.Comment = domainEvent.Comment;
                if (domainEvent.BankInformation != null)
                {
                    if (dto.BankInformation == null)
                        dto.BankInformation = new BankInformationDto();
                    dto.BankInformation.AccountNumber = domainEvent.BankInformation != null ? domainEvent.BankInformation.AccountNumber : null;
                    dto.BankInformation.BankCode = domainEvent.BankInformation != null ? domainEvent.BankInformation.BankCode : null;
                    dto.BankInformation.Iban = domainEvent.BankInformation != null ? domainEvent.BankInformation.Iban : null;
                    dto.BankInformation.Swift = domainEvent.BankInformation != null ? domainEvent.BankInformation.Swift : null;
                }
                if (domainEvent.Address != null)
                {
                    if (dto.Address == null)
                        dto.Address = new AddressDto();
                    dto.Address.Street = domainEvent.Address != null ? domainEvent.Address.Street : null;
                    dto.Address.Number = domainEvent.Address != null ? domainEvent.Address.Number : null;
                    dto.Address.Zip = domainEvent.Address != null ? domainEvent.Address.Zip : null;
                    dto.Address.City = domainEvent.Address != null ? domainEvent.Address.City : null;
                    dto.Address.Country = domainEvent.Address != null ? domainEvent.Address.Country : null;
                }

                session.Store(dto);

                session.SaveChanges(dto, domainEvent);
            }
        }

        public void Handle(SponsorDeleted domainEvent)
        {
            using (IDocumentSession session = _documentStore.OpenSession())
            {
                var dto = session.LoadById<DetailsOfSponsorDto>(domainEvent.SponsorId);
                session.Delete(dto);
                session.SaveChanges();
            }
        }

        public void Handle(SponsorshipEntered domainEvent)
        {
            using (IDocumentSession session = _documentStore.OpenSession())
            {
                var dto = session.LoadById<DetailsOfSponsorDto>(domainEvent.SponsorId);
                var personDto = session.LoadById<ListOfPersonDto>(domainEvent.PersonId);

                dto.Sponsorships.Add(new SponsorshipListItemDto 
                {
                    SponsorshipId = domainEvent.SponsorshipId,
                    PersonId = domainEvent.PersonId,
                    PersonFirstName = personDto.FirstName,
                    PersonLastName = personDto.LastName,
                    Amount = domainEvent.Amount
                });

                session.Store(dto);

                session.SaveChanges(dto, domainEvent);
            }
        }

        public void Handle(SponsorshipChanged domainEvent)
        {
            using (IDocumentSession session = _documentStore.OpenSession())
            {
                var dto = session.LoadById<DetailsOfSponsorDto>(domainEvent.SponsorId);
                var sponsorshipListItem = dto.Sponsorships.Where(sponsorshipListItemDto => sponsorshipListItemDto.SponsorshipId == domainEvent.SponsorshipId).Single();
                sponsorshipListItem.Amount = domainEvent.Amount;

                session.Store(dto);
                session.SaveChanges(dto, domainEvent);
            }
        }

        public void Handle(PersonChanged domainEvent)
        {
            using (IDocumentSession session = _documentStore.OpenSession())
            {
                var sponsorshipListItems = session.Query<DetailsOfSponsorDto>();

                foreach (var sponsorDto in sponsorshipListItems)
                {
                    var sponsorships = sponsorDto.Sponsorships.Where(sponsorship => sponsorship.PersonId == domainEvent.PersonId);

                    foreach (var sponsorship in sponsorships)
                    {
                        sponsorship.PersonFirstName = domainEvent.FirstName;
                        sponsorship.PersonLastName = domainEvent.LastName;
                    }
                }
            }
        }
    }
}
